#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
   文件名称 :     时间回调另一种简单的实现
   文件功能描述 :   功能描述
   创建人 :       小钟同学
   创建时间 :          2021/12/31
-------------------------------------------------
   修改描述-2021/12/31:
-------------------------------------------------
"""


import asyncio


import typing
from fastapi import FastAPI

from afast_core.core_plugins.pluginbase import IBasePlugin as BasePlugin


class HookEvent:

    def __init__(self,
                 on_before_request: typing.Sequence[typing.Callable] = None,
                 on_after_request: typing.Sequence[typing.Callable] = None,
                 on_teardown_appcontext: typing.Sequence[typing.Callable] = None,
                 *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.on_before_request = [] if on_before_request is None else list(on_before_request)
        self.on_after_request = [] if on_after_request is None else list(on_after_request)
        self.on_teardown_appcontext = [] if on_teardown_appcontext is None else list(on_teardown_appcontext)

    # 自定义全局的时间命名空间
    def add_event_handler(self, event_type: str, func: typing.Callable) -> None:
        assert event_type in ("before_request", "after_request", "teardown_appcontext")
        if event_type == "before_request":
            self.on_before_request.append(func)
        elif event_type == "after_request":
            self.on_after_request.append(func)
        else:
            self.on_teardown_appcontext.append(func)

    def on_event(self, event_type: str) -> typing.Callable:
        def decorator(func: typing.Callable) -> typing.Callable:
            self.add_event_handler(event_type, func)
            return func

        return decorator

    async def before_request(self, request) -> None:

        for handler in self.on_before_request:
            if asyncio.iscoroutinefunction(handler):
                await handler(request)
            else:
                handler(request)

    async def after_request(self, request, response) -> None:
        for handler in self.on_after_request:
            if asyncio.iscoroutinefunction(handler):
                await handler(request, response)
            else:
                handler(request, response)

    async def teardown_appcontext(self, request, response) -> None:
        for handler in self.on_teardown_appcontext:
            if asyncio.iscoroutinefunction(handler):
                await handler(request, response)
            else:
                handler(request, response)


class RequestHookEventPluginClient(HookEvent, BasePlugin):
    '''
    用法示例：
    core_app = FastAPI()

    rehook = RequestHookEvent(core_app=core_app)

    @rehook.on_event(event_type='before_request')  # 绑定了订阅者
    def wx_notify_third_inters_error1(reqest):
        print("RequestHookEvent！！！！！！！！！", reqest)


    @core_app.event_hook.on_event(event_type='before_request')  # 绑定了订阅者
    def wx_notify_third_inters_error1(reqest):
        print("RequestHookEvent！！！！！！！！！", reqest)
    '''
    # 插件名称
    name = '请求Hook事件插件-另一种实现方式'

    def setup(self, app: FastAPI, name: str = None, *args, **kwargs):
        """插件初始化"""
        super().setup(app, name, *args, **kwargs)
        # 插件别名赋值到APP对象里面，让它持有该对象
        app.event_hook = self
        # 业务逻辑初始化操作
        @app.middleware("http")
        async def event_request(request, call_next):
            response = None
            try:
                await self.before_request(request)
                response = await call_next(request)
                await self.after_request(request, response)
                return response
            finally:
                pass
                await self.teardown_appcontext(request, response)




__all__ = (RequestHookEventPluginClient)